
#include "TSintactico.h"



void LiberarToken(Token *token)
{
    free(token->dato);
}

void CopiarToken(Token *destino,Token *origen)
{

    destino->tipo = origen->tipo;
    destino->dato = malloc(strlen(origen->dato)+1);
    strcpy(destino->dato,origen->dato);
}

int Tsintactico_setCallback(TSintactico *ts, int evento, void* tda_contexto, TCallback callback )
{
    ts->contexto = tda_contexto;
    ts->callback_Evento_Ocurrido = callback;

    /*
        el parametro evento esta demas
    */
        return 0;
}


int TSintactico_Crear(TSintactico* as)
{

	as->longitud = 0;

    as->contexto = NULL;
    as->callback_Evento_Ocurrido = NULL;
    as->errores = NULL;
    ls_Crear(&as->listaTokens, (int)sizeof(Token),(fCopyItemLista)CopiarToken,(fDestroyItemLista)LiberarToken);

    return 0;
}

int TSintactico_Destruir(TSintactico* as)
{
    ls_Vaciar(&as->listaTokens);

    if(as->errores && !C_Vacia(as->errores[0]))
        C_Vaciar(as->errores);

    return 0;
}


int TSintactico_setError(TSintactico* as, int codigo, char* mensaje)
{
    TError error;
   error.codigo = codigo;
   error.descripcion = (char*)malloc(strlen(mensaje)+1);
   if(error.descripcion)
   {
       strcpy(error.descripcion, mensaje);
        C_Agregar(as->errores,(void*)&error);
        return TRUE;
   }

    return FALSE;
}

int TSintactico_getUltimoError(TSintactico* as, int* codigo, char* mensaje)
{
    if(as->errores->Ultimo)
    {
        *codigo = ((TError*)as->errores->Ultimo)->codigo;
        strcpy(mensaje, ((TError*)as->errores->Ultimo)->descripcion);
    }

    return 0;
}

int TSintactico_PushToken(TSintactico* as, Token* token)
{

    ls_Insertar( &as->listaTokens, LS_SIGUIENTE, (void*)token);

    return 0;
}




void AnalizarArray(TSintactico *aSintactico,int anidamiento,Boolean esElValorDeUnaClave,Boolean *huboError);
void AnalizarObjeto(TSintactico *aSintactico,int anidamiento,Boolean *huboError);

int TSintactico_terminarFlujo(TSintactico* as)
{
	int anidamiento = 0;

	Boolean huboError = False;

    ls_MoverCorriente(&as->listaTokens, LS_PRIMERO);

    while(!ls_Fin(&as->listaTokens))
    {
        anidamiento = -1;
        /*AnalizarObjeto(as, anidamiento,&huboError);*/
        AnalizarArray(as,anidamiento,False,&huboError);
    }


	return True;
}




void AnalizarObjeto(TSintactico *aSintactico,int anidamiento,Boolean *huboError)
{
    Boolean yaSeImprimioClave = False;
    Boolean seEsperaClave = False;
    Boolean seEsperaDosPuntos = False;
    Boolean seEsperaItem =False;

    Token tokenActual;

    anidamiento++;

    ls_ElemCorriente(&aSintactico->listaTokens, (void*) (&tokenActual) );


    if(tokenActual.tipo == TOKEN_OBJETO_EMPIEZA)
    {
        seEsperaClave = True;

        if (aSintactico->callback_Evento_Ocurrido)
            aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_COMIENZA_OBJETO,NULL);

    }

    while((ls_MoverCorriente(&aSintactico->listaTokens, LS_SIGUIENTE)))
    {

        ls_ElemCorriente(&aSintactico->listaTokens, ((void*) (&tokenActual)) );

        if (tokenActual.tipo == TOKEN_OBJETO_TERMINA)
            break;

        switch(tokenActual.tipo)
        {
            case TOKEN_OBJETO_EMPIEZA:
            {
                if (seEsperaClave)
                {
                    TSintactico_setError(aSintactico, 1, "Se esperaba clave");

                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);


                    *huboError = True;
                }else if (seEsperaDosPuntos)
                {
                    TSintactico_setError(aSintactico,2, "Se esperaban dos puntos");

                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);

                    *huboError = True;
                }
                else
                {
                    seEsperaClave = False;
                    seEsperaDosPuntos = False;
                    seEsperaItem = False;
                    AnalizarObjeto(aSintactico,anidamiento+1,huboError);
                }
                break;
            }
            case TOKEN_DOSPUNTOS:
            {
                if (seEsperaClave)
                {

                    TSintactico_setError(aSintactico, 1, "Se esperaba clave");

                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);

                    *huboError = True;
                }else if (seEsperaItem)
                {
                    TSintactico_setError(aSintactico, 3, "Se esperaba item");

                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);

                    *huboError = True;
                }
                else
                {
                    seEsperaClave = False;
                    seEsperaDosPuntos = False;
                    seEsperaItem = True;

                }


                break;
            }
            case TOKEN_STRING:
            {
                if (seEsperaDosPuntos)
                {
                    TSintactico_setError(aSintactico, 2, "Se esperaban dos puntos");

                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);


                    *huboError = True;
                }
                else if (!yaSeImprimioClave)
                {


                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_CLAVE,(void*)tokenActual.dato);

                    yaSeImprimioClave = True;
                    seEsperaClave = False;
                    seEsperaItem = False;
                    seEsperaDosPuntos = True;
                }
                else
                {
                    seEsperaItem = False;


                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_STRING,(void*)tokenActual.dato);
                }

                break;
            }
            case TOKEN_NUMERO:
            {
                if (seEsperaClave)
                {
                    TSintactico_setError(aSintactico, 1, "Se esperaba clave");

                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);


                    *huboError = True;
                }else if (seEsperaDosPuntos)
                {
                    TSintactico_setError(aSintactico, 2, "Se esperaban dos puntos");

                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);


                    *huboError = True;
                }
                else
                {
                    seEsperaItem = False;

                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_NUMERO,(void*)tokenActual.dato);


                }
                break;
            }
            case TOKEN_NULL:
            {
                if (seEsperaClave)
                {
                    TSintactico_setError(aSintactico, 1, "Se esperaba clave");

                   if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);


                    *huboError = True;
                }else if (seEsperaDosPuntos)
                {
                    TSintactico_setError(aSintactico, 2, "Se esperaban dos puntos");

                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);


                    *huboError = True;
                }
                else
                {
                    seEsperaItem = False;

                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_NULL,NULL);
                }
                break;


            }
            case TOKEN_COMA:
            {

                if (seEsperaClave)
                {
                    TSintactico_setError(aSintactico, 1, "Se esperaba clave");


                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);


                    *huboError = True;
                }else if (seEsperaDosPuntos)
                {
                    TSintactico_setError(aSintactico, 2, "Se esperaban dos puntos");


                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);


                    *huboError = True;
                }
                else if (seEsperaItem)
                {
                    TSintactico_setError(aSintactico, 3, "Se esperaba item");

                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);


                    *huboError = True;
                }
                else
                {


                    seEsperaClave = True;
                    yaSeImprimioClave = False;
                }

                break;
            }
            case TOKEN_TRUE:
            {
                if (seEsperaClave)
                {
                    TSintactico_setError(aSintactico, 1, "Se esperaba clave");


                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);


                    *huboError = True;
                }else if (seEsperaDosPuntos)
                {
                    TSintactico_setError(aSintactico, 2, "Se esperaban dos puntos");

                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);


                    *huboError = True;
                }
                else
                {
                    seEsperaItem = False;
                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_TRUE,"true");
                }

                break;
            }
            case TOKEN_FALSE:
            {
                if (seEsperaClave)
                {
                    TSintactico_setError(aSintactico, 1, "Se esperaba clave");

                   if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);


                    *huboError = True;
                }else if (seEsperaDosPuntos)
                {
                    TSintactico_setError(aSintactico, 2, "Se esperaban dos puntos");

                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);


                    *huboError = True;
                }
                else
                {
                    seEsperaItem = False;


                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_FALSE,"false");
                }
                break;
            }

            case TOKEN_ERROR_LEXICO:
            {

               if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);


                *huboError = True;
                break;
            }
            case TOKEN_ARRAY_EMPIEZA:
            {

                if (seEsperaClave)
                {
                    TSintactico_setError(aSintactico, 1, "Se esperaba clave");

                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);


                    *huboError = True;
                }else if (seEsperaDosPuntos)
                {
                    TSintactico_setError(aSintactico, 2, "Se esperaban dos puntos");

                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);


                    *huboError = True;
                }
                else
                {
                    seEsperaItem = False;
                    AnalizarArray(aSintactico,anidamiento,yaSeImprimioClave,huboError);
                }
                break;
            }
        }


    }

    anidamiento--;

    if(tokenActual.tipo == TOKEN_OBJETO_TERMINA)
    {

        if (aSintactico->callback_Evento_Ocurrido)
            aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_TERMINA_OBJETO,NULL);
    }


}

void AnalizarArray(TSintactico *aSintactico,int anidamiento,Boolean esElValorDeUnaClave,Boolean *huboError)
{


    Token tokenActual;

    Boolean seEsperaItem = False;

    if(esElValorDeUnaClave)
        anidamiento = anidamiento + 7;


    ls_ElemCorriente(&aSintactico->listaTokens, (void*) &tokenActual);


    if(tokenActual.tipo == TOKEN_ARRAY_EMPIEZA)
    {

        if (aSintactico->callback_Evento_Ocurrido)
            aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_COMIENZA_ARRAY,NULL);



    }

    anidamiento++;

    while((ls_MoverCorriente(&aSintactico->listaTokens, LS_SIGUIENTE)) )
    {


        ls_ElemCorriente(&aSintactico->listaTokens, (void*) &tokenActual);

        if (tokenActual.tipo == TOKEN_ARRAY_TERMINA)
            break;


        switch(tokenActual.tipo)
        {
            case TOKEN_ARRAY_EMPIEZA:
            {
                seEsperaItem = False;
                AnalizarArray(aSintactico,anidamiento,False,huboError);

                break;
            }
            case TOKEN_OBJETO_EMPIEZA:
            {
                seEsperaItem = False;
                AnalizarObjeto(aSintactico,anidamiento+1,huboError);
                break;
            }
            case TOKEN_STRING:
            {
                seEsperaItem = False;



                if (aSintactico->callback_Evento_Ocurrido)
                    aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_STRING,(void*)tokenActual.dato);

                break;
            }
            case TOKEN_NUMERO:
            {
                seEsperaItem = False;



                if (aSintactico->callback_Evento_Ocurrido)
                    aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_NUMERO,(void*)tokenActual.dato);

                break;
            }

            case TOKEN_ERROR_LEXICO:
            {
                seEsperaItem = False;

                if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);

                 *huboError = True;
                break;
            }
            case TOKEN_COMA:
            {
                if (seEsperaItem)
                {
                    TSintactico_setError(aSintactico, 3, "Se esperaba item");

                    if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);

                    *huboError = True;
                }
                else
                {
                    seEsperaItem = True;

                }

                break;
            }

            case TOKEN_NULL:
            {
                seEsperaItem = False;


                if (aSintactico->callback_Evento_Ocurrido)
                    aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_NULL,NULL);

                break;
            }

            case TOKEN_TRUE:
            {
                seEsperaItem = False;


                if (aSintactico->callback_Evento_Ocurrido)
                    aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_TRUE,"true");

                break;
            }
            case TOKEN_FALSE:
            {
                seEsperaItem = False;


                if (aSintactico->callback_Evento_Ocurrido)
                    aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_FALSE,"false");
                break;
            }
        }

    }

    if (seEsperaItem)
    {
        TSintactico_setError(aSintactico, 3, "Se esperaba item");

        if (aSintactico->callback_Evento_Ocurrido)
                        aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_ERROR,NULL);

         *huboError = True;
    }

    if(tokenActual.tipo == TOKEN_ARRAY_TERMINA)
    {
        if (!esElValorDeUnaClave)
            anidamiento--;


       if (aSintactico->callback_Evento_Ocurrido)
            aSintactico->callback_Evento_Ocurrido(aSintactico->contexto,CB_TERMINA_ARRAY,NULL);

    }


}

int TSintactico_setColaErrores(TSintactico* as, TCola* cola){
    as->errores = cola;

    return 0;
}


